package com.cx.mall.pay.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.cx.mall.common.entity.order.entity.OrderInfo;
import com.cx.mall.common.entity.pay.entity.PayLog;
import com.cx.mall.pay.config.AlipayConfiguration;
import com.cx.mall.pay.service.IAliPayService;
import com.cx.mall.pay.service.IPayLogService;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.transaction.Transaction;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
("aliPayService")
public class IAliPayServiceImpl implements IAliPayService {
    @Autowired
    private AlipayConfiguration alipayConfiguration;
    @Autowired
    private IPayLogService payLogService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StreamBridge streamBridge;

    @Override
    public String pay(OrderInfo orderInfo) {
        //1.初始化客户端
        try {
            DefaultAlipayClient defaultAlipayClient = new DefaultAlipayClient(
                alipayConfiguration.getAlipayConfig());
            
            // 2.创建api对应的request
            AlipayTradePagePayRequest alipayTradePagePayRequest = new AlipayTradePagePayRequest();
            
            // 3.设置回调地址
            alipayTradePagePayRequest.setReturnUrl(alipayConfiguration.getReturnUrl());
            alipayTradePagePayRequest.setNotifyUrl(alipayConfiguration.getNotifyUrl());
            
            // 4.设置请求参数
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("out_trade_no", orderInfo.getOrderId());
            jsonObject.put("total_amount", orderInfo.getTotalAmount());
            jsonObject.put("subject", orderInfo.getRecipients());
            jsonObject.put("product_code", "FAST_INSTANT_TRADE_PAY");
            
            alipayTradePagePayRequest.setBizContent(jsonObject.toString());
            log.info("支付参数:{}", jsonObject.toString());
            
            // 5.调用支付接口
            String form = defaultAlipayClient.pageExecute(alipayTradePagePayRequest).getBody();
            log.info("支付宝下单成功,订单信息:{}", orderInfo);
            log.info("支付宝下单成功,支付宝返回的表单信息:{}", form);
            return form;
            
        } catch (AlipayApiException e) {
            log.error("支付宝支付失败: {}", e.getMessage(), e);
            if (e.getMessage().contains("timeout") || e.getMessage().contains("504")) {
                throw new RuntimeException("支付网关超时，请稍后重试");
            }
            throw new RuntimeException("初始化支付客户端失败: " + e.getMessage());
        } catch (JSONException e) {
            log.error("创建JSON对象失败: {}", e.getMessage(), e);
            throw new RuntimeException("创建JSON对象失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("支付过程中发生未知错误: {}", e.getMessage(), e);
            throw new RuntimeException("支付失败，请稍后重试");
        }
    }

    @Override
    @Transactional
    public void payNotify(Map<String, String[]> parameterMap) {
        try {
            //获取支付宝返回的各个参数

            String tradeNo = parameterMap.get("trade_no")[0];
            String outTradeNo = parameterMap.get("out_trade_no")[0];
            String totalAmount = parameterMap.get("total_amount")[0];
            String subject = parameterMap.get("subject")[0];
            String tradeStatus = parameterMap.get("trade_status")[0];
            
            //写支付日志
            PayLog payLog = new PayLog();
            payLog.setOrderId(outTradeNo);
            payLog.setAmount(BigDecimal.valueOf(Double.parseDouble(totalAmount)));
            payLog.setCreateTime(LocalDateTime.now());
            payLog.setId(tradeNo);
            payLogService.save(payLog);
            log.info("支付日志:{}", payLog);

            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                @Override
                public void afterCommit() {
                    Message<?> message = MessageBuilder
                            .withPayload(outTradeNo) //消息体
                            .setHeader("tradeNo_Id", tradeNo) //消息头
                            .build();
                    //异步通知 保证  setnx key value  幂等性发送：在10分钟 内发送一次 如果存在，什么也不做
                    if(redisTemplate.opsForValue().setIfAbsent("pay_"+tradeNo, "1", 10, TimeUnit.MINUTES)) { //如果不存在
                       log.info("发送支付通知消息:{}", message);
                        streamBridge.send("payNotifyOutPut-out-0", message);
                    }
                }
            });
        } catch (Exception e) {
            log.error("处理支付通知失败: {}", e.getMessage(), e);
            throw new RuntimeException("处理支付通知失败: " + e.getMessage());
        }
    }
}

